package com.yilian.bionio;

import java.io.*;
import java.net.*;
import java.util.concurrent.*;

/**
 * 简单BIO阻塞演示案例
 * 
 * 这个类通过多个客户端的网络操作来验证BIO的阻塞特性：
 * 1. 服务器accept()阻塞 - 等待客户端连接
 * 2. 多个客户端并发连接 - 展示"一个连接一个线程"模型
 * 3. 客户端read()阻塞 - 等待数据可用
 * 4. 观察阻塞行为和线程模型
 * 
 * @author 练习项目
 * @version 1.0
 */
public class SimpleBlockingDemo {
    
    private static final int PORT = 8888;
    private static final int CLIENT_COUNT = 3; // 客户端数量
    
    public static void main(String[] args) {
        System.out.println("=== 简单BIO阻塞演示（多客户端） ===\n");
        
        // 启动服务器
        startServer();
        
        // 等待服务器启动
        try {
            Thread.sleep(2000);
            
            // 启动多个客户端
            startMultipleClients();
            
        } catch (InterruptedException e) {
            System.err.println("演示被中断: " + e.getMessage());
        }
    }
    
    /**
     * 启动BIO服务器
     */
    private static void startServer() {
        new Thread(() -> {
            try (ServerSocket serverSocket = new ServerSocket(PORT)) {
                System.out.println("服务器启动，监听端口: " + PORT);
                System.out.println("服务器正在等待客户端连接...");
                System.out.println("注意：此时accept()方法会阻塞，直到有客户端连接");
                
                // 使用线程池处理多个客户端连接
                ExecutorService executor = Executors.newCachedThreadPool();
                
                // 接受多个客户端连接
                for (int i = 0; i < CLIENT_COUNT; i++) {
                    System.out.println("\n--- 等待第" + (i + 1) + "个客户端连接 ---");
                    System.out.println("注意：accept()会阻塞，直到有客户端连接");
                    
                    // accept()会阻塞在这里
                    Socket clientSocket = serverSocket.accept();
                    System.out.println("客户端" + (i + 1) + "已连接: " + clientSocket.getInetAddress());
                    
                    // 为每个客户端创建一个新线程处理
                    final int clientId = i + 1;
                    executor.submit(() -> handleClient(clientSocket, clientId));
                }
                
                // 关闭线程池
                executor.shutdown();
                executor.awaitTermination(10, TimeUnit.SECONDS);
                System.out.println("\n所有客户端处理完成，服务器关闭");
                
            } catch (IOException | InterruptedException e) {
                System.err.println("服务器异常: " + e.getMessage());
            }
        }).start();
    }
    
    /**
     * 处理单个客户端连接
     */
    private static void handleClient(Socket clientSocket, int clientId) {
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(clientSocket.getInputStream()));
             PrintWriter writer = new PrintWriter(clientSocket.getOutputStream(), true)) {
            
            System.out.println("   线程" + Thread.currentThread().getName() + " 开始处理客户端" + clientId);
            
            System.out.println("   等待客户端" + clientId + "发送数据...");
            System.out.println("   注意：此时readLine()方法会阻塞，直到有数据可读");
            
            // readLine()会阻塞在这里
            String message = reader.readLine();
            System.out.println("   收到客户端" + clientId + "消息: " + message);
            
            // 发送响应
            String response = "服务器已收到客户端" + clientId + "的消息: " + message;
            writer.println(response);
            System.out.println("   发送响应给客户端" + clientId + ": " + response);
            
            // 关闭连接
            clientSocket.close();
            System.out.println("   客户端" + clientId + "连接已关闭");
            
        } catch (IOException e) {
            System.err.println("   处理客户端" + clientId + "异常: " + e.getMessage());
        }
    }
    
    /**
     * 启动多个BIO客户端
     */
    private static void startMultipleClients() {
        System.out.println("启动" + CLIENT_COUNT + "个客户端...");
        
        // 使用线程池管理多个客户端
        ExecutorService clientExecutor = Executors.newFixedThreadPool(CLIENT_COUNT);
        
        for (int i = 1; i <= CLIENT_COUNT; i++) {
            final int clientId = i;
            clientExecutor.submit(() -> startClient(clientId));
        }
        
        // 关闭客户端执行器
        clientExecutor.shutdown();
        
        try {
            // 等待所有客户端完成
            clientExecutor.awaitTermination(15, TimeUnit.SECONDS);
            System.out.println("\n所有客户端已完成");
        } catch (InterruptedException e) {
            System.err.println("等待客户端完成时被中断: " + e.getMessage());
        }
    }
    
    /**
     * 启动单个BIO客户端
     */
    private static void startClient(int clientId) {
        try {
            System.out.println("\n客户端" + clientId + "开始连接服务器...");
            
            // 连接服务器
            Socket socket = new Socket("localhost", PORT);
            System.out.println("客户端" + clientId + "连接成功");
            
            // 等待一段时间，让用户观察阻塞状态
            System.out.println("客户端" + clientId + "等待" + (clientId * 2) + "秒后发送数据...");
            Thread.sleep(clientId * 2000); // 不同客户端等待不同时间
            
            // 发送数据
            PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
            String message = "Hello from Client " + clientId + "!";
            writer.println(message);
            System.out.println("客户端" + clientId + "发送: " + message);
            
            // 读取服务器响应
            BufferedReader reader = new BufferedReader(
                new InputStreamReader(socket.getInputStream()));
            String response = reader.readLine();
            System.out.println("客户端" + clientId + "收到: " + response);
            
            // 关闭连接
            socket.close();
            System.out.println("客户端" + clientId + "连接已关闭");
            
        } catch (IOException | InterruptedException e) {
            System.err.println("客户端" + clientId + "异常: " + e.getMessage());
        }
    }
} 